package com.yeziji.devops.sql.base;

import cn.hutool.core.util.StrUtil;
import com.yeziji.devops.constant.SqlExecuteTypeEnum;
import com.yeziji.devops.sql.SqlBuilderFactory;
import com.yeziji.devops.sql.constructor.InsertSqlConstructor;
import com.yeziji.devops.sql.constructor.SelectSqlConstructor;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;

import javax.validation.constraints.NotEmpty;
import java.util.List;

/**
 * 自定义 SQL 构造器
 *
 * <p>通过调用 {@link SqlBuilderFactory} 构建指定的 sql 语句，该类是所有构造语句的基类。如 {@link InsertSqlConstructor} 、
 * {@link SelectSqlConstructor} 都要继承该类用于实现构造 sql。一般简单、常用的 sql 语句可以通过 {@link #wrapper} 来实现，如果需要执行复杂的
 * sql，则建议使用自定义 {@link #sql} 来实现
 *
 * @author hwy
 * @since 2024/07/27 0:18
 **/
@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder(toBuilder = true)
public class SqlConstructorBase {
    /**
     * sql 类型
     * <p>select、update、insert 和 delete</p>
     *
     * @see com.yeziji.devops.constant.SqlExecuteTypeEnum
     */
    protected String type;

    /**
     * 查询、插入或更新的字段
     * <p>
     * 新增、修改时必须传入该值;
     * </p>
     */
    @NotEmpty(message = "修改、新增数据时必须传入 columns")
    protected List<String> columns;

    /**
     * sql 执行的数据表
     * <p>必须指定数据表</p>
     */
    protected String table;

    /**
     * sql 执行的自定义条件
     * <pre>
     *     username = "gzkemays" and delete = true
     * </pre>
     */
    protected String wrapper;

    /**
     * 自定义 sql 语句
     * <pre>
     *     select * from forum_user where username = "gzkemays" and delete = true
     * </pre>
     */
    protected String sql;

    /**
     * 子类应用或重写 check 方式
     */
    protected void check() {
        if (SqlExecuteTypeEnum.getByValue(type.toUpperCase()) == null) {
            throw new NullPointerException("类型不存在");
        }
    }

    public String buildSql() {
        if (StrUtil.isNotBlank(this.sql)) {
            return sql;
        }
        check();
        return new SqlBuilderFactory()
                .getSqlBuilder(SqlExecuteTypeEnum.getByValue(type), this)
                .execute();
    }
}
